home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / GUSI 1.4.1 / GUSI / GUSIUnix.cp < prev    next >
Encoding:
Text File  |  1994-02-25  |  24.0 KB  |  1,174 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    GUSI                -    Grand Unified Socket Interface
  3. File        :    GUSIUnix.cp        -    Implementation of Unix domain calls
  4. Author    :    Matthias Neeracher
  5. Language    :    MPW C/C++
  6.  
  7. $Log: GUSIUnix.cp,v $
  8. Revision 1.1  1994/02/25  02:31:11  neeri
  9. Initial revision
  10.  
  11. Revision 0.13  1993/02/07  00:00:00  neeri
  12. New configuration scheme
  13.  
  14. Revision 0.12  1993/01/17  00:00:00  neeri
  15. Be more careful about User interrupts
  16.  
  17. Revision 0.11  1992/11/15  00:00:00  neeri
  18. Rename GUSIFSp_P.h to TFileSpec.h (there we go again)
  19.  
  20. Revision 0.10  1992/09/13  00:00:00  neeri
  21. Always complete write
  22.  
  23. Revision 0.9  1992/09/12  00:00:00  neeri
  24. Renamed Paths.h to GUSIFSp_P.h
  25.  
  26. Revision 0.8  1992/08/10  00:00:00  neeri
  27. select() for accept/connect
  28.  
  29. Revision 0.7  1992/07/26  00:00:00  neeri
  30. Error in using memccpy()
  31.  
  32. Revision 0.6  1992/07/13  00:00:00  neeri
  33. In spirit of Unix implementation, use file, not hash table
  34.  
  35. Revision 0.5  1992/05/21  00:00:00  neeri
  36. Implemented select()
  37.  
  38. Revision 0.4  1992/04/24  00:00:00  neeri
  39. Introducing UnixStreamSocket, UnixDgramSocket
  40.  
  41. Revision 0.3  1992/04/20  00:00:00  neeri
  42. C++ rewrite
  43.  
  44. Revision 0.2  1992/04/18  00:00:00  neeri
  45. On with the show, good health to you
  46.  
  47. Revision 0.1  1992/03/31  00:00:00  neeri
  48. unix domain socket calls
  49.  
  50. *********************************************************************/
  51.  
  52. #include "GUSI_P.h"
  53. #include "TFileSpec.h"
  54.  
  55. #include <Processes.h>
  56. #include <Resources.h>
  57. #include <SysEqu.h>
  58. #include <Finder.h>
  59.  
  60. #pragma segment GUSIUnix
  61.  
  62. class UnixSocketDomain : public SocketDomain {
  63. public:
  64.     UnixSocketDomain()    :    SocketDomain(AF_UNIX)    {        }
  65.  
  66.     virtual Socket *     socket(int type, short protocol);
  67.     virtual int         choose(
  68.                                 int         type, 
  69.                                 char *     prompt, 
  70.                                 void *     constraint,        
  71.                                 int         flags,
  72.                                  void *     name, 
  73.                                 int *     namelen);
  74. };
  75.  
  76. static UnixSocketDomain    UnixSockets;
  77.  
  78. class UnixSocket;                                    // That's what this file's all about
  79. class UnixStreamSocket;
  80. class UnixDgramSocket;
  81.  
  82. struct UnixSocketAddr : TFileSpec {
  83.     Boolean        valid;
  84.     Boolean        owned;
  85.     
  86.     UnixSocketAddr();
  87.     UnixSocketAddr(TFileSpec spec);
  88. };
  89.  
  90. // The interface of this class should never be changed now the first version 
  91. // of GUSI is released. All further changes should be done by making a subclass.
  92. // The Version() method must return *increasing* version numbers.
  93.  
  94. // Version 2 adds support for aborting a connection, see below
  95.  
  96. class UnixChannel : public SingleObject {
  97.     UnixSocketAddr    address;
  98.     
  99.     void UnBind();
  100. protected:
  101.     UnixSocket *     sock;
  102. public:
  103.     UnixChannel    *    nextListener;
  104.     int                errno;
  105.     
  106.     UnixChannel(UnixSocket * owner);
  107.     virtual ~UnixChannel();
  108.     
  109.     virtual int            Version();
  110.     
  111.     virtual Boolean    Bind(UnixSocketAddr & addr);
  112.     virtual Boolean    Connect(UnixChannel * ch);
  113.     virtual Boolean    Accept(UnixChannel * ch);
  114.  
  115.     virtual int            Read(void * buffer, int len);
  116.     virtual int            Write(void * buffer, int len);
  117.     virtual int            Send(UnixChannel * from, void * buffer, int len);
  118.     virtual int         ReadAvail();
  119.     virtual int            WriteAvail();
  120.     virtual int            BufSize();
  121.     virtual void         DiscardRead(int len);
  122.     virtual void         ShutDown(int how);
  123.     virtual void        Disconnect();
  124.     
  125.     virtual int            GUSI_error(int err);
  126.  
  127.     virtual UnixSocketAddr & 
  128.                             Address();
  129. };
  130.  
  131. class UnixChannel2 : public UnixChannel {
  132. public:
  133.     UnixChannel2(UnixSocket * owner);
  134.  
  135.     virtual int            Version();
  136.     virtual void        Orphan();
  137.     virtual void        AbortConnect(UnixChannel * ch);
  138. };
  139.  
  140. class UnixSocket : public Socket {
  141.     friend class UnixChannel;
  142.     friend class UnixChannel2;
  143. protected:
  144.     char                status;
  145.     char                state;
  146.     Boolean            nonblocking;
  147.     char                protocol;
  148.     Ptr                readBuf;
  149.     short                readBufSize;
  150.     short                readPos;
  151.     short             validBytes;
  152.     short                curListener;
  153.     short                maxListener;
  154.     UnixChannel *    chan;
  155.     UnixChannel    *    peer;
  156.     UnixChannel *    firstListener;
  157.     UnixChannel *    lastListener;
  158.  
  159.                     UnixSocket(short prot);
  160.     void            defaultbind();
  161. public:
  162.     enum {channelUnknown, channelAncient, channelSupportsConnAbort};
  163.     
  164.     virtual int    bind(void * name, int namelen);
  165.     virtual int getsockname(void * name, int * namelen);
  166.     virtual int getpeername(void * name, int * namelen);
  167.     virtual int    fcntl(unsigned int cmd, int arg);
  168.     virtual int    ioctl(unsigned int request, void *argp);
  169.     virtual int shutdown(int how);
  170.     virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
  171.     virtual         ~UnixSocket();
  172. };
  173.  
  174. class UnixStreamSocket : public UnixSocket {
  175.     friend class UnixSocketDomain;
  176.     
  177.                     UnixStreamSocket();
  178. public:
  179.     virtual int listen(int qlen);
  180.     virtual int connect(void * address, int addrlen);
  181.     virtual Socket * accept(void * address, int * addrlen);
  182.     virtual int recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen);
  183.     virtual int sendto(void * buffer, int buflen, int flags, void * to, int tolen);
  184.     
  185.     virtual         ~UnixStreamSocket();
  186. };
  187.  
  188. class UnixDgramSocket : public UnixSocket {
  189.     friend class UnixSocketDomain;
  190.     
  191.                     UnixDgramSocket();
  192. public:
  193.     virtual int connect(void * address, int addrlen);
  194.     virtual int recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen);
  195.     virtual int sendto(void * buffer, int buflen, int flags, void * to, int tolen);
  196.     
  197.     virtual         ~UnixDgramSocket();
  198. };
  199.  
  200. struct UnixSocketID {
  201.     UnixChannel    *            chan;
  202.     
  203.     AddrBlock                machine;
  204.     ProcessSerialNumber    process;
  205.     
  206.                 UnixSocketID()                                        {}
  207.                 UnixSocketID(UnixChannel * ch);
  208.     Boolean    Validate();
  209. };
  210.  
  211. /********************** UnixSocketAddr members ***********************/
  212.  
  213. inline UnixSocketAddr::UnixSocketAddr() 
  214.     : valid(false), owned(true)            
  215. {
  216. }
  217.  
  218. inline UnixSocketAddr::UnixSocketAddr(TFileSpec spec) 
  219.     : TFileSpec(spec), valid(false), owned(true)            
  220. {
  221. }
  222.  
  223. /************************ UnixSocket members ************************/
  224.  
  225. static UnixSocketAddr * CanonizeName(void * name, int len);
  226. static void                 UncanonizeName(UnixSocketAddr & name, void * addr, int * addrlen);
  227. static UnixChannel *     LookupName(UnixSocketAddr name);
  228.  
  229. UnixSocket::UnixSocket(short prot)
  230. {
  231.     GUSI_error(0);
  232.     
  233.     readBufSize        =    DEFAULT_BUFFER_SIZE;
  234.     status            =    SOCK_STATUS_USED;
  235.     state                =    SOCK_STATE_UNCONNECTED;
  236.     nonblocking        =    false;
  237.     protocol            =    prot;
  238.     readPos            =    0;
  239.     validBytes        =    0;
  240.     curListener        =    0;
  241.     maxListener        =    0;
  242.     firstListener    =    nil;
  243.     lastListener    =    nil;
  244.     chan                =    nil;
  245.     peer                =    nil;
  246.     readBuf            =    NewPtr(readBufSize);
  247.     
  248.     if (!readBuf)
  249.         GUSI_error(ENOMEM);
  250. }
  251.  
  252. UnixSocket::~UnixSocket()
  253. {
  254.     if (readBuf)
  255.         DisposPtr(readBuf);
  256.     
  257.     if (protocol == SOCK_STREAM)
  258.         if (peer)
  259.             peer->Disconnect();
  260.         else 
  261.             while (firstListener) {
  262.                 firstListener->Disconnect();
  263.                 
  264.                 firstListener = firstListener->nextListener;
  265.             }
  266.         
  267.     if (chan)
  268.         delete chan;
  269. }
  270.  
  271. void UnixSocket::defaultbind()
  272. {
  273.     struct sockaddr_un    addr;
  274.     
  275.     addr.sun_family    =    AF_UNIX;
  276.     tmpnam(addr.sun_path);
  277.     
  278.     bind(&addr, strlen(addr.sun_path)+2);
  279. }
  280.  
  281. int UnixSocket::fcntl(unsigned int cmd, int arg)
  282. {
  283.     switch (cmd)    {
  284.     case F_GETFL:
  285.         if (nonblocking)
  286.             return FNDELAY;
  287.         else
  288.             return 0;
  289.     case F_SETFL:
  290.         if (arg & FNDELAY)
  291.             nonblocking = true;
  292.         else
  293.             nonblocking = false;
  294.             
  295.         return 0;
  296.     default:
  297.         return GUSI_error(EOPNOTSUPP);
  298.     }
  299. }
  300.  
  301. int UnixSocket::ioctl(unsigned int request, void *argp)
  302. {
  303.     switch (request)    {
  304.     case FIONBIO:
  305.         nonblocking    =    (Boolean) *(long *) argp;
  306.         
  307.         return 0;
  308.     case FIONREAD:
  309.         if (chan)
  310.             *(long *) argp = chan->ReadAvail();
  311.         else
  312.             *(long *) argp    = 0;
  313.  
  314.         return 0;
  315.     default:
  316.         return GUSI_error(EOPNOTSUPP);
  317.     }
  318. }
  319.  
  320. int UnixSocket::bind(void *sa_name, int sa_namelen)
  321. {
  322.     UnixSocketAddr *    addr;
  323.     
  324.     if (chan && chan->Address().valid)
  325.             return GUSI_error(EINVAL);
  326.     
  327.     addr    =    CanonizeName(sa_name, sa_namelen);
  328.     
  329.     if (!addr)
  330.         return -1;
  331.     
  332.     if (LookupName(*addr))
  333.         return GUSI_error(EADDRINUSE);
  334.  
  335.     if (!chan && !(chan = new UnixChannel2(this)))
  336.         return GUSI_error(ENOMEM);
  337.     
  338.     if (!chan->Bind(*addr))
  339.         return GUSI_error(ENOMEM);
  340.     
  341.     return 0;
  342. }
  343.  
  344. int UnixSocket::getsockname(void *name, int *namelen)
  345. {
  346.     UncanonizeName(chan->Address(), name, namelen);
  347.     
  348.     return 0;
  349. }
  350.  
  351. int UnixSocket::getpeername(void *name, int *namelen)
  352. {
  353.     if (!peer)
  354.         return GUSI_error(ENOTCONN);
  355.         
  356.     UncanonizeName(peer->Address(), name, namelen);
  357.     
  358.     return 0;
  359. }
  360.  
  361. int UnixSocket::select(Boolean * canRead, Boolean * canWrite, Boolean *)
  362. {
  363.     int    goodies = 0;
  364.     
  365.     if (canRead)
  366.         if ((state == SOCK_STATE_LIS_CON) || !chan || chan->ReadAvail())    {
  367.             *canRead    =     true;
  368.             ++goodies;
  369.         } 
  370.     
  371.     if (canWrite)
  372.         if (!peer || peer->WriteAvail())    {
  373.             *canWrite    =     true;
  374.             ++goodies;
  375.         } 
  376.     
  377.     return goodies;
  378. }
  379.  
  380. int UnixSocket::shutdown(int how)
  381. {
  382.     if (!chan)
  383.         return GUSI_error(ENOTCONN);
  384.  
  385.     chan->ShutDown(how);
  386.     
  387.     return 0;
  388. }
  389.  
  390. /********************* UnixStreamSocket members *********************/
  391.  
  392. UnixStreamSocket::UnixStreamSocket()
  393.     :    UnixSocket(SOCK_STREAM)
  394. {
  395. }
  396.  
  397. UnixStreamSocket::~UnixStreamSocket()
  398. {
  399. }
  400.  
  401. int UnixStreamSocket::listen(int qlen)
  402. {
  403.     if (state != SOCK_STATE_UNCONNECTED)
  404.         return GUSI_error(EISCONN);
  405.         
  406.     state            =    SOCK_STATE_LISTENING;
  407.     maxListener    =    qlen;
  408.     
  409.     return 0;
  410. }
  411.  
  412. int UnixStreamSocket::connect(void *sa_name, int sa_namelen)
  413. {
  414.     UnixSocketAddr *    addr;
  415.     UnixChannel    *    other;
  416.     
  417.     if (peer)
  418.         return GUSI_error(EISCONN);
  419.     
  420.     addr    =    CanonizeName(sa_name, sa_namelen);
  421.     
  422.     if (!addr)
  423.         return -1;
  424.     
  425.     other = LookupName(*addr);
  426.     
  427.     if (!other)
  428.         return GUSI_error(EADDRNOTAVAIL);
  429.  
  430.     if (!chan && !(chan = new UnixChannel2(this)))
  431.         return GUSI_error(ENOMEM);
  432.     
  433.     if (!chan->Address().valid)
  434.         defaultbind();
  435.     
  436.     if (!other->Connect(chan))
  437.         return GUSI_error(ECONNREFUSED);
  438.         
  439.     state    =    SOCK_STATE_CONNECTING;
  440.     
  441.     if (nonblocking)
  442.         return GUSI_error(EINPROGRESS);
  443.         
  444.     SAFESPIN(state == SOCK_STATE_CONNECTING, SP_MISC, 0);
  445.     
  446.     if (state == SOCK_STATE_CONNECTED)
  447.         return 0;
  448.     else if (!errno)
  449.         return GUSI_error(ECONNREFUSED);
  450.         
  451.     // User abort, a tricky situation. What we do depends on the peer channel
  452.     // version.
  453.     
  454.     if (other->Version() >= channelSupportsConnAbort)    // The new way
  455.         ((UnixChannel2 *) other)->AbortConnect(chan);    // This type cast is safe
  456.     else                                                                // The old way
  457.         ((UnixChannel2 *) chan)->Orphan();                    // This type cast is safe            
  458.     
  459.     return -1;
  460. }
  461.  
  462. Socket * UnixStreamSocket::accept(void * address, int * addrlen)
  463. {
  464.     UnixStreamSocket *    newsock;
  465.     
  466.     if (state != SOCK_STATE_LISTENING && state != SOCK_STATE_LIS_CON)
  467.         return (Socket *) GUSI_error_nil(ENOTCONN);
  468.  
  469. restart:    
  470.     if (!curListener)
  471.         if (nonblocking)
  472.             return (Socket *) GUSI_error_nil(EWOULDBLOCK);
  473.         else
  474.             SPINP(state == SOCK_STATE_LISTENING, SP_MISC, 0);
  475.             
  476.     if (!curListener)
  477.             return (Socket *) GUSI_error_nil(EFAULT);                    // I *really* hope this won't happen 
  478.  
  479.     newsock    =    new UnixStreamSocket;
  480.     
  481.     if (!newsock)
  482.         return (Socket *) GUSI_error_nil(ENOMEM);
  483.     
  484.     newsock->state            =    SOCK_STATE_CONNECTED;
  485.     newsock->peer            =    firstListener;
  486.     newsock->chan            =    new UnixChannel2(newsock);
  487.     
  488.     if (!newsock->chan)    {
  489.         delete newsock;
  490.         
  491.         return (Socket *) GUSI_error_nil(ENOMEM);
  492.     }
  493.     
  494.     newsock->chan->Address()            =    chan->Address();
  495.     newsock->chan->Address().owned    =    false;
  496.     
  497.     firstListener    =    firstListener->nextListener;
  498.     
  499.     if (!firstListener)
  500.         lastListener = nil;
  501.     
  502.     if (!--curListener)
  503.         state = SOCK_STATE_LISTENING;
  504.     
  505.     if (newsock->peer->Accept(newsock->chan) == -1)    {
  506.         newsock->peer = nil;
  507.         
  508.         delete newsock;
  509.         
  510.         goto restart;
  511.     }
  512.  
  513.     UncanonizeName(newsock->peer->Address(), address, addrlen);
  514.     
  515.     return newsock;
  516. }
  517.  
  518. int UnixStreamSocket::recvfrom(void * buffer, int buflen, int flags, void * from, int *)
  519. {
  520.     int                avail;
  521.     
  522.     if (flags || from)
  523.         return GUSI_error(EOPNOTSUPP);
  524.     if (!chan || !peer)
  525.         return GUSI_error(ENOTCONN);    
  526.         
  527.     if ((avail = chan->ReadAvail()) == -1)
  528.         if (chan->errno == ESHUTDOWN)
  529.             return 0;
  530.         else
  531.             return GUSI_error(chan->errno);
  532.     
  533.     if (nonblocking && !avail)
  534.         return GUSI_error(EWOULDBLOCK);
  535.     
  536.     errno    =    0;
  537.     SPIN(!(avail = chan->Read(buffer, buflen)), SP_STREAM_READ, 0);
  538.     if (avail == -1 && !errno)
  539.         if (chan->errno == ESHUTDOWN)
  540.             return 0;
  541.         else
  542.             GUSI_error(chan->errno);
  543.             
  544.     return avail;
  545. }
  546.  
  547. int UnixStreamSocket::sendto(void * buffer, int buflen, int flags, void * to, int)
  548. {
  549.     int     avail;
  550.     int    done;
  551.     
  552.     if (flags || to)
  553.         return GUSI_error(EOPNOTSUPP);
  554.     if (!chan || !peer)
  555.         return GUSI_error(ENOTCONN);    
  556.         
  557.     if ((avail = peer->WriteAvail()) == -1)
  558.         return GUSI_error(peer->errno);
  559.     
  560.     if (nonblocking && !avail)
  561.         return GUSI_error(EWOULDBLOCK);
  562.     
  563.     for (
  564.         done = errno = 0; 
  565.         !errno && buflen; 
  566.         buflen -= avail, buffer = Ptr(buffer) + avail
  567.     )    {
  568.         SPIN(!(avail = peer->Write(buffer, buflen)), SP_STREAM_WRITE, 0);
  569.         if (avail == -1) {
  570.             if (!errno)
  571.                 GUSI_error(peer->errno);
  572.                 
  573.             break;
  574.         } 
  575.         
  576.         done += avail;
  577.         
  578.         if (nonblocking)
  579.             break;
  580.     }
  581.             
  582.     return done ? done : (buflen ? -1 : 0);
  583. }
  584.  
  585. /********************* UnixDgramSocket members **********************/
  586.  
  587. UnixDgramSocket::UnixDgramSocket()
  588.     :    UnixSocket(SOCK_DGRAM)
  589. {
  590. }
  591.  
  592. UnixDgramSocket::~UnixDgramSocket()
  593. {
  594. }
  595.  
  596. int UnixDgramSocket::connect(void *sa_name, int sa_namelen)
  597. {
  598.     UnixSocketAddr *    addr;
  599.     
  600.     addr    =    CanonizeName(sa_name, sa_namelen);
  601.     
  602.     if (!addr)
  603.         return -1;
  604.     
  605.     peer = LookupName(*addr);
  606.     
  607.     if (!peer)
  608.         return GUSI_error(EADDRNOTAVAIL);
  609.     
  610.     state    =    SOCK_STATE_CONNECTED;
  611.     
  612.     return 0;
  613. }
  614.  
  615. int UnixDgramSocket::recvfrom(void * buffer, int buflen, int flags, void * from, int * fromlen)
  616. {
  617.     UnixChannel *     partner;
  618.     int                length;
  619.     int                avail;
  620.     
  621.     if (flags)
  622.         return GUSI_error(EOPNOTSUPP);
  623.     if (!chan || !chan->Address().valid)
  624.         return GUSI_error(ENOTCONN);    // fuck UNIX semantics; it's impossible for another
  625.                                                 // socket to communicate with this one, anyway
  626.         
  627.     if ((avail = chan->ReadAvail()) == -1)
  628.         return GUSI_error(chan->errno);
  629.     
  630.     // Datagram sockets communicate the sender's address in the first 4 bytes
  631.     // The transfer will be atomic, so only one spin is needed
  632.     
  633.     if (nonblocking && !avail)
  634.         return GUSI_error(EWOULDBLOCK);
  635.     
  636.     errno    =    0;
  637.     SPIN(!(avail = chan->Read(&partner, sizeof(UnixChannel *))), SP_DGRAM_READ, 0);
  638.     if (errno)
  639.         return -1;
  640.     else if (avail == -1)
  641.         return GUSI_error(chan->errno);
  642.     else if (avail < sizeof(UnixChannel *))
  643.         return GUSI_error(EFAULT);
  644.  
  645.     if ((avail = chan->Read(&length, sizeof(long))) == -1)
  646.         return GUSI_error(chan->errno);
  647.     
  648.     buflen = min(buflen, length);
  649.     
  650.     if ((avail = chan->Read(buffer, buflen)) == -1)
  651.         return GUSI_error(chan->errno);
  652.         
  653.     chan->DiscardRead(length - buflen);
  654.     
  655.     UncanonizeName(partner->Address(), from, fromlen);
  656.         
  657.     return avail;
  658. }
  659.  
  660. int UnixDgramSocket::sendto(void * buffer, int buflen, int flags, void * to, int tolen)
  661. {
  662.     UnixSocketAddr *    addr;
  663.     UnixChannel *         partner;
  664.     int                    length;
  665.     int                    avail;
  666.     
  667.     if (flags)
  668.         return GUSI_error(EOPNOTSUPP);
  669.     if (!chan)
  670.         chan = new UnixChannel2(this);
  671.     if (peer)    
  672.         partner    =    peer;
  673.     else {
  674.         addr    =    CanonizeName(to, tolen);
  675.         
  676.         if (!addr)
  677.             return -1;
  678.         
  679.         partner = LookupName(*addr);
  680.         
  681.         if (!partner)
  682.             return GUSI_error(EADDRNOTAVAIL);
  683.     }
  684.             
  685.     length    =    sizeof(UnixChannel *) + sizeof(int) + buflen;
  686.     
  687.     if (length > partner->BufSize())
  688.         return GUSI_error(EMSGSIZE);
  689.     if ((avail = partner->WriteAvail()) == -1)
  690.         return GUSI_error(partner->errno);
  691.     if (avail < length)
  692.         if (nonblocking)
  693.             return GUSI_error(EWOULDBLOCK);
  694.         else
  695.             SPIN((avail=partner->WriteAvail()) != -1 && avail<length, SP_DGRAM_WRITE, 0);
  696.     
  697.     if (avail == -1)
  698.         return GUSI_error(partner->errno);
  699.         
  700.     errno    =    0;
  701.     SPIN(!(avail = partner->Send(chan, buffer, buflen)), SP_DGRAM_WRITE, 0);
  702.     if (errno)
  703.         return -1;
  704.     else if (avail == -1)
  705.         return GUSI_error(partner->errno);
  706.         
  707.     return avail;
  708. }
  709.  
  710. /*********************** UnixChannel members ************************/
  711.  
  712. UnixChannel::UnixChannel(UnixSocket * owner)
  713.     :    address(UnixSocketAddr()), sock(owner)
  714. {
  715. }
  716.  
  717. UnixChannel::~UnixChannel()
  718. {
  719.     if (address.valid)
  720.         UnBind();
  721. }
  722.  
  723. void UnixChannel::UnBind()
  724. {
  725.     if (address.owned)
  726.         HDelete(address.vRefNum, address.parID, address.name);        
  727. }
  728.  
  729. int UnixChannel::Version()
  730. {
  731.     return 1;
  732. }
  733.  
  734. Boolean UnixChannel::Bind(UnixSocketAddr & addr)
  735. {
  736.     short                resFile;
  737.     short                oldResFile    =    CurResFile();
  738.     Handle            ID;
  739.     UnixSocketID    me(this);
  740.     FInfo                info;
  741.     
  742.     address    =    addr;
  743.     
  744.     if (PtrToHand(&me, &ID, sizeof(UnixSocketID)))
  745.         return false;
  746.         
  747.     HDelete(address.vRefNum, address.parID, address.name);
  748.     HCreate(address.vRefNum, address.parID, address.name, 'GU∑I', '∑OCK');
  749.     HCreateResFile(address.vRefNum, address.parID, address.name);
  750.     resFile = HOpenResFile(address.vRefNum, address.parID, address.name, fsRdWrPerm);
  751.     
  752.     if (resFile == -1)    {
  753.         DisposeHandle(ID);
  754.         return false;
  755.     }
  756.     
  757.     AddResource(ID, 'GU∑I', GUSIRsrcID, "\p");
  758.     
  759.     if (ResError()) {
  760.         CloseResFile(resFile);
  761.         HDelete(address.vRefNum, address.parID, address.name);
  762.         DisposeHandle(ID);
  763.         UseResFile(oldResFile);
  764.         return false;
  765.     }
  766.  
  767.     CopyIconFamily(*(short *) CurApRefNum, GUSIRsrcID, resFile, kCustomIconResource);
  768.     
  769.     CloseResFile(resFile);
  770.     UseResFile(oldResFile);
  771.  
  772.     HGetFInfo(address.vRefNum, address.parID, address.name, &info);
  773.     info.fdFlags    |=    (1 << 10);
  774.     info.fdFlags    &= ~(1 << 8);
  775.     HSetFInfo(address.vRefNum, address.parID, address.name, &info);
  776.         
  777.     return true;
  778. }
  779.  
  780. Boolean UnixChannel::Connect(UnixChannel * ch)
  781. {
  782.     if (sock->curListener >= sock->maxListener)
  783.         return false;
  784.         
  785.     switch (sock->state)    {
  786.     case SOCK_STATE_LISTENING:
  787.         sock->state    =    SOCK_STATE_LIS_CON;
  788.         // Fall through
  789.     case SOCK_STATE_LIS_CON:
  790.         if (!sock->lastListener)
  791.             sock->firstListener    =    ch;
  792.         else
  793.             sock->lastListener->nextListener = ch;
  794.             
  795.         sock->lastListener = ch;
  796.         ++sock->curListener;
  797.         
  798.         return true;
  799.     default:
  800.         return false;
  801.     }
  802. }
  803.  
  804. Boolean UnixChannel::Accept(UnixChannel * ch)
  805. {
  806.     if (!sock)
  807.         return true;
  808.         
  809.     sock->peer    =    ch;
  810.     sock->state    =    SOCK_STATE_CONNECTED;
  811.     
  812.     return true;
  813. }
  814.  
  815. int UnixChannel::Read(void * buffer, int len)
  816. {
  817.     if (sock->status & SOCK_STATUS_NOREAD)
  818.         return GUSI_error(ESHUTDOWN);
  819.         
  820.     Ptr    startBuf    = (Ptr) buffer;
  821.     int    section;
  822.         
  823.     if (sock->validBytes > 0)    {
  824.         section    =    sock->readBufSize-sock->readPos;
  825.         
  826.         if (section > sock->validBytes)
  827.             section = sock->validBytes;
  828.         if (section > len)
  829.             section = len;
  830.         
  831.         BlockMove(sock->readBuf+sock->readPos, buffer, section);
  832.         
  833.         buffer                = (char *) buffer + section;
  834.         sock->readPos        +=    section;
  835.         sock->validBytes    -=    section;
  836.         len                     -= section;
  837.         
  838.         if (sock->readPos == sock->readBufSize)
  839.             sock->readPos    =    0;
  840.     } else if (sock->state != SOCK_STATE_CONNECTED)
  841.         return GUSI_error(ESHUTDOWN);
  842.         
  843.     if (len > 0 && sock->validBytes > 0)    {
  844.         section     =    (len > sock->validBytes) ? sock->validBytes : len;
  845.         
  846.         BlockMove(sock->readBuf, buffer, section);
  847.         
  848.         buffer                = (char *) buffer + section;
  849.         sock->readPos        +=    section;
  850.         sock->validBytes    -=    section;
  851.     }
  852.         
  853.     return (char *) buffer-startBuf;        
  854. }
  855.  
  856. int UnixChannel::Write(void * buffer, int len)
  857. {    
  858.     if (!sock || (sock->status & SOCK_STATUS_NOWRITE))
  859.         return GUSI_error(ESHUTDOWN);
  860.  
  861.     Ptr    startBuf    =    (Ptr) buffer;
  862.     int    avail        =    sock->readBufSize - sock->validBytes;
  863.     int    section    =    avail - sock->readPos;
  864.         
  865.     if (section > 0)    {
  866.         if (section > len)
  867.             section = len;
  868.             
  869.         BlockMove(buffer, sock->readBuf+sock->readPos+sock->validBytes, section);
  870.         
  871.         buffer                 = (char *) buffer + section;
  872.         sock->validBytes    +=    section;
  873.         len                     -= section;
  874.         avail                    -=    section;
  875.     }
  876.     
  877.     if (len > 0 && avail > 0)    {
  878.         section     =    (len > avail) ? avail : len;
  879.         
  880.         BlockMove(buffer, sock->readBuf+sock->readPos-avail, section);
  881.         
  882.         buffer                 = (char *) section;
  883.         sock->validBytes    +=    section;
  884.     }
  885.         
  886.     return (char *) buffer-startBuf;        
  887. }
  888.  
  889. int UnixChannel::Send(UnixChannel * from, void * buffer, int len)
  890. {
  891.     int length    =    sizeof(UnixChannel *) + sizeof(int) + len;
  892.  
  893.     if (sock->peer && sock->peer != from)
  894.         return GUSI_error(ECONNREFUSED);
  895.     
  896.     if (WriteAvail() < length)
  897.         return 0;
  898.     
  899.     Write(&from, sizeof(UnixChannel *));
  900.     Write(&len, sizeof(int));
  901.     
  902.     return Write(buffer, len);
  903. }
  904.  
  905. int UnixChannel::ReadAvail()
  906. {
  907.     if (sock->status & SOCK_STATUS_NOREAD)
  908.         return GUSI_error(ESHUTDOWN);
  909.         
  910.     return sock->validBytes;
  911. }
  912.  
  913. int UnixChannel::WriteAvail()
  914. {
  915.     if (!sock || (sock->status & SOCK_STATUS_NOWRITE))
  916.         return GUSI_error(ESHUTDOWN);
  917.         
  918.     return sock->readBufSize - sock->validBytes;
  919. }
  920.  
  921. int UnixChannel::BufSize()
  922. {
  923.     return sock->readBufSize;
  924. }
  925.  
  926. void UnixChannel::ShutDown(int how)
  927. {
  928.     switch(how) {
  929.     case 0 : 
  930.         sock->status |= SOCK_STATUS_NOREAD;
  931.         break;
  932.     case 1 : 
  933.         sock->status |= SOCK_STATUS_NOWRITE;
  934.         break;
  935.     case 2 :
  936.         sock->status |= SOCK_STATUS_NOREAD | SOCK_STATUS_NOWRITE;
  937.     }
  938. }
  939.  
  940. void UnixChannel::DiscardRead(int len)
  941. {
  942.     if (sock->validBytes <= len)    {
  943.         sock->validBytes    =    0;
  944.         sock->readPos        =    0;
  945.     } else {
  946.         sock->validBytes    -=    len;
  947.         sock->readPos        = (sock->readPos+len) % sock->readBufSize;
  948.     }
  949. }
  950.  
  951. void UnixChannel::Disconnect()
  952. {
  953.     if (sock) {
  954.         sock->peer    =    nil;
  955.         sock->state    =    SOCK_STATE_UNCONNECTED;
  956.     }
  957. }
  958.  
  959. int UnixChannel::GUSI_error(int err)
  960. {
  961.     errno    =    err;
  962.  
  963.     return -1;
  964. }
  965.  
  966. UnixSocketAddr & UnixChannel::Address()
  967. {
  968.     return address;
  969. }
  970.  
  971. /*********************** UnixChannel2 members ************************/
  972.  
  973. UnixChannel2::UnixChannel2(UnixSocket * owner)
  974.     :    UnixChannel(owner)
  975. {
  976. }
  977.  
  978. int UnixChannel2::Version()
  979. {
  980.     return 2;
  981. }
  982.  
  983. void UnixChannel2::Orphan()
  984. {
  985.     // Sever ties to owner
  986.     
  987.     sock->chan    =    nil;
  988.     sock             =     nil;
  989. }
  990.  
  991. void UnixChannel2::AbortConnect(UnixChannel * ch)
  992. {
  993.     UnixChannel    * prev = nil;
  994.     
  995.     for (UnixChannel * chan = sock->firstListener; chan; chan = chan->nextListener) {
  996.         if (chan == ch)    {    // Got it !
  997.             if (prev)
  998.                 prev->nextListener    =    chan->nextListener;
  999.             else
  1000.                 sock->firstListener    =    chan->nextListener;
  1001.             
  1002.             if (!chan->nextListener)
  1003.                 sock->lastListener    =    prev;
  1004.             
  1005.             if (!--sock->curListener)
  1006.                 sock->state = SOCK_STATE_LISTENING;
  1007.             
  1008.             break;
  1009.         }
  1010.         prev = chan;
  1011.     }
  1012. }
  1013.  
  1014. /********************* UnixSocketID members **********************/
  1015.  
  1016. UnixSocketID::UnixSocketID(UnixChannel * ch)
  1017.     : chan(ch)
  1018. {
  1019.     short    net;
  1020.     short node;
  1021.     
  1022.     AppleTalkIdentity(net, node);
  1023.     
  1024.     machine.aNet    =    net;
  1025.     machine.aNode    =    node;
  1026.     machine.aSocket=    0;
  1027.     
  1028.     if (!hasProcessMgr || GetCurrentProcess(&process))    {
  1029.         process.highLongOfPSN = kNoProcess;
  1030.         process.lowLongOfPSN = kNoProcess;
  1031.     }    
  1032. }
  1033.  
  1034. Boolean UnixSocketID::Validate()
  1035. {
  1036.     UnixSocketID    me(nil);
  1037.     ProcessInfoRec    info;
  1038.     
  1039.     if (memcmp(&machine, &me.machine, sizeof(AddrBlock)))
  1040.         return false;
  1041.         
  1042.     if (!hasProcessMgr)
  1043.         return (!process.highLongOfPSN && !process.lowLongOfPSN);
  1044.     
  1045.     info.processInfoLength    =    sizeof(ProcessInfoRec);
  1046.     info.processName            =    nil;
  1047.     info.processAppSpec        =    nil;
  1048.     
  1049.     return !GetProcessInformation(&process, &info);
  1050. }
  1051.  
  1052. /********************* UnixSocketDomain member **********************/
  1053.  
  1054. extern "C" void GUSIwithUnixSockets()
  1055. {
  1056.     UnixSockets.DontStrip();
  1057. }
  1058.  
  1059. Socket * UnixSocketDomain::socket(int type, short)
  1060. {
  1061.     UnixSocket * sock    =    nil;
  1062.     
  1063.     switch (type)    {
  1064.     case SOCK_STREAM:
  1065.         sock = new UnixStreamSocket();
  1066.         break;
  1067.     case SOCK_DGRAM:
  1068.         sock = new UnixDgramSocket();
  1069.         break;
  1070.     default:
  1071.         GUSI_error(ESOCKTNOSUPPORT);
  1072.     }    
  1073.     
  1074.     if (sock && errno)    {
  1075.         delete sock;
  1076.         
  1077.         return nil;
  1078.     } else
  1079.         return sock;
  1080. }
  1081.  
  1082. int UnixSocketDomain::choose(int, char * prompt, void *, int flags, void * name, int * namelen)
  1083. {
  1084.     struct sockaddr_un *    addr = (sockaddr_un *) name;
  1085.     sa_constr_file            constr;
  1086.     
  1087.     addr->sun_family    = AF_UNIX;
  1088.  
  1089.     constr.numTypes    =    1;
  1090.     constr.types[0]    =    '∑OCK';
  1091.     
  1092.     *namelen -= 2;
  1093.     if (FileSockets.choose(0, prompt, &constr, flags, addr->sun_path, namelen))
  1094.         return -1;
  1095.     
  1096.     *namelen += 2;
  1097.     
  1098.     return 0;
  1099. }
  1100.  
  1101.  
  1102. /************************* Name conversions *************************/
  1103.  
  1104. static char                    canonPath[120];
  1105. static UnixSocketAddr    canonAddr;
  1106.  
  1107. static UnixSocketAddr * CanonizeName(void * name, int len)
  1108. {
  1109.     struct sockaddr_un *    addr = (sockaddr_un *) name;
  1110.     
  1111.     if (!name || !len || addr->sun_family != AF_UNIX)    {
  1112.         GUSI_error(EAFNOSUPPORT);
  1113.         
  1114.         return nil;
  1115.     }
  1116.     
  1117.     len -= 2;
  1118.     memcpy(canonPath, addr->sun_path, len);
  1119.     
  1120.     canonPath[len] =     0;
  1121.     canonAddr        =    TFileSpec(canonPath);
  1122.     
  1123.     if (canonAddr.Error())
  1124.         return nil;
  1125.     else
  1126.         canonAddr.valid    =    true;
  1127.         
  1128.     return &canonAddr;
  1129. }
  1130.  
  1131. static void UncanonizeName(UnixSocketAddr & name, void * addr, int * addrlen)
  1132. {
  1133.     struct sockaddr_un *    uaddr = (sockaddr_un *) addr;
  1134.     char    *                     path    =    name.FullPath();
  1135.     char     *                     end;
  1136.     
  1137.     if (!addr || *addrlen < sizeof(short))    {
  1138.         if (addrlen)
  1139.             *addrlen = 0;
  1140.         
  1141.         return;
  1142.     }
  1143.     
  1144.     *addrlen             -= 2;
  1145.     uaddr->sun_family =     AF_UNIX;
  1146.     
  1147.     if (end = (char *) memccpy(uaddr->sun_path, path, 0, *addrlen))
  1148.         *addrlen = end-uaddr->sun_path-1;
  1149.     
  1150.     *addrlen             +=     2;
  1151. }
  1152.  
  1153. static UnixChannel * LookupName(UnixSocketAddr name)
  1154. {
  1155.     short                file;
  1156.     Handle            hdl;
  1157.     UnixChannel *    cur    =    nil;
  1158.     UnixSocketID    id;
  1159.  
  1160.     file    =    HOpenResFile(name.vRefNum, name.parID, name.name, fsRdPerm);
  1161.  
  1162.     if (file != -1)    {
  1163.         if (hdl = Get1Resource('GU∑I', GUSIRsrcID))    {
  1164.             id = **(UnixSocketID **) hdl;
  1165.             
  1166.             if (id.Validate())
  1167.                 cur = id.chan;
  1168.         }
  1169.         CloseResFile(file);
  1170.     }
  1171.     
  1172.     return cur;
  1173. }
  1174.